/*
 *  SimpleVector.cpp
 *  Pirates2011
 *
 *  Created by Alan Dorin on 25/03/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

using namespace std;

#include <cmath>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>

#include "SimpleVector.h"

const double SimpleVector::ZERO_SimpleVector_MAGNITUDE = 1.0e-32;

SimpleVector::SimpleVector(void)
{   v[vX] = v[vY] = v[vZ] = mag = 0.0; }

SimpleVector::SimpleVector(double a)
{
    v[vX] = v[vY] = v[vZ] = a;
    mag = sqrt(3*a*a);
}

SimpleVector::SimpleVector(double a, double b, double c)
{
    v[vX] = a;	v[vY] = b;   v[vZ] = c;
    mag = sqrt(v[vX]*v[vX] + v[vY]*v[vY] + v[vZ]*v[vZ]);
}

SimpleVector::SimpleVector(const SimpleVector& source)
{
    v[vX] = source.v[vX];	v[vY] = source.v[vY]; v[vZ] = source.v[vZ];
    mag = source.mag;
}

SimpleVector::~SimpleVector()
{
	// nothing to do here
}

void SimpleVector::output(ostream& outFile, bool commasOn)
const
{
    if(commasOn) outFile << "( ";
    outFile << v[vX];
    if(commasOn) outFile << ", ";
    else outFile << " ";
    
    outFile << v[vY];
    if(commasOn) outFile << ", ";
    else outFile << " ";
    
    outFile << v[vZ];
    if(commasOn) outFile << " )  mag=" << mag;
}


void SimpleVector::output(void)
const
{
    output(cout);
}

void SimpleVector::set(double a, double b, double c)										// set vector components separately
{
	v[vX]=a; v[vY]=b; v[vZ]=c;
	mag = sqrt(v[vX]*v[vX] + v[vY]*v[vY] + v[vZ]*v[vZ]);
}

void SimpleVector::setZero(void)
{ v[vX]=v[vY]=v[vZ]=mag=0; }

void SimpleVector::set(double a)															// set vector components equivalently
{ v[vX] = v[vY] = v[vZ] = a; mag = sqrt(3*v[vX]*v[vX]); }

void SimpleVector::vector_gl_colour(void) const											// gl colour call for vector
{	glColor3d(v[vX], v[vY], v[vZ]);}

void SimpleVector::vector_gl_v3(void)	const												// glVertex3dv() call for vector
{	glVertex3dv(v); }

void SimpleVector::vector_gl_translate(void) const										// gl translate call for vector
{	glTranslated(v[vX], v[vY], v[vZ]); }	

int	SimpleVector::equalZero (void) const													// is vector a zero vector?
{ return ((mag < SimpleVector::ZERO_SimpleVector_MAGNITUDE) ? 1 : 0); }

double	SimpleVector::magnitude (void) const												// length of v
{ return mag; }

SimpleVector	SimpleVector::unit (void) const													// (normalized) unit vector
{
	if(equalZero())
	{	cout << "\nERROR: vector div by 0"; this->output();
		cout << "\nAttempt to zeroVector.unit()\n"; exit(1);
	}
	return (SimpleVector(v[vX]/mag, v[vY]/mag, v[vZ]/mag));
}

SimpleVector	SimpleVector::operator- (void) const												// antiparallel vector (ie. -ve each component)
{ return (SimpleVector(-v[vX], -v[vY], -v[vZ])); }

SimpleVector	SimpleVector::operator- (const SimpleVector& w) const									// difference b/n v & w
{ return (SimpleVector(v[vX]-(w.v[vX]), v[vY]-(w.v[vY]), v[vZ]-(w.v[vZ]))); }

SimpleVector	SimpleVector::operator+ (const SimpleVector& w) const									// sum of v & w
{ return (SimpleVector(v[vX]+(w.v[vX]), v[vY]+(w.v[vY]), v[vZ]+(w.v[vZ]))); }

SimpleVector	SimpleVector::operator* (double s) const											// scalar mult. v*s
{ return (SimpleVector(v[vX]*s, v[vY]*s, v[vZ]*s)); }

SimpleVector	SimpleVector::operator/ (double s) const											// scalr div. v/s
{
	if(s==0.0)
	{cout << "\nERROR: (SimpleVector::operator /) vector div by 0\n"; exit(1);}

	return (SimpleVector(v[vX]/s, v[vY]/s, v[vZ]/s));
}

SimpleVector&	SimpleVector::operator= (const SimpleVector& w)											// assignment op.
{
	v[vX]=w.v[vX]; v[vY]=w.v[vY]; v[vZ]=w.v[vZ]; mag=w.mag;
	return *this;
}

// ******** non-member functions *******************************
// *************************************************************

ostream& operator<< (ostream& outFile, const SimpleVector& theVector)
{
    return outFile << theVector.v[vX]
		   << "\t" << theVector.v[vY]
		   << "\t" << theVector.v[vZ];
}

istream& operator>> (istream& inFile, SimpleVector& theVector)
{
    double x, y, z;
    
    inFile >> x >> y >> z;
    theVector.set(x, y, z);
    
    return inFile;
}

bool operator== (const SimpleVector& v, const SimpleVector& w)
{
	return ((v.v[vX] == w.v[vX]) && (v.v[vY] == w.v[vY]) && (v.v[vZ] == w.v[vZ]) ? true : false);
}
